#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
七星彩号码预测模块
实现多种预测算法来预测下期可能的中奖号码
"""

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
import random
from collections import Counter
import math
from datetime import datetime
from .database import DatabaseManager
import logging

logger = logging.getLogger(__name__)

class LotteryPredictor:
    def __init__(self):
        self.db_manager = DatabaseManager()
        self.scaler = StandardScaler()
    
    def predict_next_numbers(self, lottery_type='qxc', method='ensemble'):
        """预测下期号码"""
        logger.info(f"开始预测 {lottery_type} 下期号码，使用方法: {method}")
        
        # 获取所有历史数据
        history_data = self.db_manager.get_all_data(lottery_type=lottery_type)
        
        if len(history_data) < 10:
            logger.warning("历史数据不足，无法进行预测")
            return None
        
        # 根据彩票类型选择相应的预测方法
        if lottery_type == 'qxc':
            return self.predict_qxc_numbers(history_data, method)
        else:
            logger.error(f"不支持的彩票类型: {lottery_type}")
            return None
    
    def predict_qxc_numbers(self, historical_data, method='ensemble'):
        """预测七星彩号码"""
        predictions = {}
        
        if method == 'frequency' or method == 'ensemble':
            freq_pred = self.frequency_analysis_qxc(historical_data)
            predictions['frequency'] = freq_pred
        
        if method == 'pattern' or method == 'ensemble':
            pattern_pred = self.pattern_analysis_qxc(historical_data)
            predictions['pattern'] = pattern_pred
        
        if method == 'ml' or method == 'ensemble':
            ml_pred = self.machine_learning_qxc(historical_data)
            predictions['ml'] = ml_pred
        
        if method == 'hot_cold' or method == 'ensemble':
            hot_cold_pred = self.hot_cold_analysis_qxc(historical_data)
            predictions['hot_cold'] = hot_cold_pred
        
        if method == 'position' or method == 'ensemble':
            position_pred = self.position_analysis_qxc(historical_data)
            predictions['position'] = position_pred
        
        if method == 'min_frequency' or method == 'ensemble':
            min_freq_pred = self.min_frequency_analysis_qxc(historical_data)
            predictions['min_frequency'] = min_freq_pred
        
        # 如果是集成方法，综合多种预测结果
        if method == 'ensemble':
            final_prediction = self.ensemble_prediction_qxc(predictions)
        else:
            final_prediction = predictions.get(method, predictions[list(predictions.keys())[0]])
        
        # 保存预测结果
        self.db_manager.save_prediction('qxc', final_prediction, method, 0.75)
        
        return {
            'lottery_type': 'qxc',
            'method': method,
            'prediction': final_prediction,
            'individual_predictions': predictions if method == 'ensemble' else None,
            'confidence': self.calculate_confidence(historical_data, final_prediction)
        }
    
    def frequency_analysis_qxc(self, historical_data):
        """频率分析法预测七星彩"""
        # 统计每个位置上每个数字的出现频率
        position_counters = [Counter() for _ in range(7)]
        
        for record in historical_data:
            numbers = record['numbers']
            for i, digit in enumerate(numbers):
                position_counters[i][int(digit)] += 1
        
        # 为每个位置选择出现频率最高的数字
        predicted_numbers = []
        for i in range(7):
            if position_counters[i]:
                # 从前3个最常见的数字中随机选择
                most_common = position_counters[i].most_common(3)
                weights = [count for _, count in most_common]
                numbers = [num for num, _ in most_common]
                predicted_digit = random.choices(numbers, weights=weights)[0]
                predicted_numbers.append(predicted_digit)
            else:
                # 根据位置设置不同的随机范围
                if i == 6:  # 第7位数字范围是0-14
                    predicted_numbers.append(random.randint(0, 14))
                else:  # 前6位数字范围是0-9
                    predicted_numbers.append(random.randint(0, 9))
        
        return predicted_numbers
    
    def pattern_analysis_qxc(self, historical_data):
        """模式分析法预测七星彩"""
        recent_data = historical_data  # 使用所有历史数据
        
        # 分析每个位置的数字分布模式
        position_patterns = []
        for pos in range(7):
            digits = [int(record['numbers'][pos]) for record in recent_data]
            
            # 分析奇偶比例
            odd_count = sum(1 for d in digits if d % 2 == 1)
            odd_ratio = odd_count / len(digits)
            
            # 根据位置调整大小比例的定义
            if pos == 6:  # 第7位数字范围是0-14
                # 0-7为小，8-14为大
                big_count = sum(1 for d in digits if d >= 8)
            else:  # 前6位数字范围是0-9
                # 0-4为小，5-9为大
                big_count = sum(1 for d in digits if d >= 5)
            big_ratio = big_count / len(digits)
            
            position_patterns.append({
                'odd_ratio': odd_ratio,
                'big_ratio': big_ratio,
                'avg': np.mean(digits),
                'std': np.std(digits)
            })
        
        # 根据模式生成号码
        predicted_numbers = []
        for i, pattern in enumerate(position_patterns):
            # 根据位置设置候选数字范围
            if i == 6:  # 第7位数字范围是0-14
                if random.random() < pattern['odd_ratio']:
                    # 生成奇数
                    candidates = [1, 3, 5, 7, 9, 11, 13]
                else:
                    # 生成偶数
                    candidates = [0, 2, 4, 6, 8, 10, 12, 14]
                
                if random.random() < pattern['big_ratio']:
                    # 倾向于大数(8-14)
                    candidates = [c for c in candidates if c >= 8]
                    if not candidates:
                        candidates = [8, 9, 10, 11, 12, 13, 14]
                else:
                    # 倾向于小数(0-7)
                    candidates = [c for c in candidates if c < 8]
                    if not candidates:
                        candidates = [0, 1, 2, 3, 4, 5, 6, 7]
            else:  # 前6位数字范围是0-9
                if random.random() < pattern['odd_ratio']:
                    # 生成奇数
                    candidates = [1, 3, 5, 7, 9]
                else:
                    # 生成偶数
                    candidates = [0, 2, 4, 6, 8]
                
                if random.random() < pattern['big_ratio']:
                    # 倾向于大数(5-9)
                    candidates = [c for c in candidates if c >= 5]
                    if not candidates:
                        candidates = [5, 6, 7, 8, 9]
                else:
                    # 倾向于小数(0-4)
                    candidates = [c for c in candidates if c < 5]
                    if not candidates:
                        candidates = [0, 1, 2, 3, 4]
            
            predicted_numbers.append(random.choice(candidates))
        
        return predicted_numbers
    
    def machine_learning_qxc(self, historical_data):
        """机器学习预测七星彩"""
        if len(historical_data) < 50:
            # 数据不足时使用频率分析
            return self.frequency_analysis_qxc(historical_data)
        
        try:
            # 准备训练数据
            X, y = self.prepare_ml_data_qxc(historical_data)
            
            if len(X) < 20:
                return self.frequency_analysis_qxc(historical_data)
            
            # 为每个位置训练一个模型
            models = []
            for pos in range(7):
                model = RandomForestRegressor(n_estimators=50, random_state=42, max_depth=8)
                model.fit(X, y[:, pos])
                models.append(model)
            
            # 预测下期号码
            last_features = X[-1:]
            predicted_numbers = []
            
            for i, model in enumerate(models):
                pred = model.predict(last_features)[0]
                # 根据位置将预测值转换为相应范围内的整数
                if i == 6:  # 第7位数字范围是0-14
                    digit = int(round(max(0, min(14, pred))))
                else:  # 前6位数字范围是0-9
                    digit = int(round(max(0, min(9, pred))))
                predicted_numbers.append(digit)
            
            return predicted_numbers
            
        except Exception as e:
            logger.error(f"机器学习预测失败: {e}")
            return None
    
    def hot_cold_analysis_qxc(self, historical_data):
        """冷热号分析预测七星彩"""
        recent_data = historical_data  # 使用所有历史数据
        
        # 统计每个位置上每个数字的出现频率
        position_counters = [Counter() for _ in range(7)]
        
        for record in recent_data:
            numbers = record['numbers']
            for i, digit in enumerate(numbers):
                position_counters[i][int(digit)] += 1
        
        predicted_numbers = []
        for i in range(7):
            # 根据位置设置数字范围
            if i == 6:  # 第7位数字范围是0-14
                all_digits = list(range(15))
            else:  # 前6位数字范围是0-9
                all_digits = list(range(10))
            
            digit_frequencies = {num: position_counters[i].get(num, 0) for num in all_digits}
            
            # 排序获取热号和冷号
            sorted_digits = sorted(digit_frequencies.items(), key=lambda x: x[1], reverse=True)
            hot_digits = [num for num, _ in sorted_digits[:4]]  # 前4个热号
            cold_digits = [num for num, _ in sorted_digits[-4:]]  # 后4个冷号
            medium_digits = [num for num, _ in sorted_digits[3:7]]  # 中等频率
            
            # 随机选择策略：40%热号，30%中等，30%冷号
            rand = random.random()
            if rand < 0.4 and hot_digits:
                predicted_digit = random.choice(hot_digits)
            elif rand < 0.7 and medium_digits:
                predicted_digit = random.choice(medium_digits)
            elif cold_digits:
                predicted_digit = random.choice(cold_digits)
            else:
                if i == 6:  # 第7位数字范围是0-14
                    predicted_digit = random.randint(0, 14)
                else:  # 前6位数字范围是0-9
                    predicted_digit = random.randint(0, 9)
            
            predicted_numbers.append(predicted_digit)
        
        return predicted_numbers
    
    def position_analysis_qxc(self, historical_data):
        """位置分析法预测七星彩"""
        # 分析每个位置的数字变化趋势
        predicted_numbers = []
        
        for pos in range(7):
            recent_digits = [int(record['numbers'][pos]) for record in historical_data]
            
            if len(recent_digits) >= 3:
                # 计算趋势
                trend = (recent_digits[0] - recent_digits[2]) / 2
                next_digit = recent_digits[0] + trend
                
                # 添加随机扰动
                next_digit += random.uniform(-1, 1)
                
                # 根据位置确保在正确范围内
                if pos == 6:  # 第7位数字范围是0-14
                    next_digit = int(round(max(0, min(14, next_digit))))
                else:  # 前6位数字范围是0-9
                    next_digit = int(round(max(0, min(9, next_digit))))
            else:
                if pos == 6:  # 第7位数字范围是0-14
                    next_digit = random.randint(0, 14)
                else:  # 前6位数字范围是0-9
                    next_digit = random.randint(0, 9)
            
            predicted_numbers.append(next_digit)
        
        return predicted_numbers
    
    def min_frequency_analysis_qxc(self, historical_data):
        """最低频率分析法预测七星彩
        分析历史中奖记录中每个位置数字的出现频率，选择每个位置出现频率最少的数字组成号码
        """
        # 统计每个位置上每个数字的出现频率
        position_counters = [Counter() for _ in range(7)]
        
        for record in historical_data:
            numbers = record['numbers']
            for i, digit in enumerate(numbers):
                position_counters[i][int(digit)] += 1
        
        # 为每个位置选择出现频率最低的数字
        predicted_numbers = []
        for i in range(7):
            if position_counters[i]:
                # 确定该位置的数字范围
                if i == 6:  # 第7位数字范围是0-14
                    digit_range = range(0, 15)
                else:  # 前6位数字范围是0-9
                    digit_range = range(0, 10)
                
                # 统计所有可能数字的频率，未出现的数字频率为0
                digit_frequencies = {}
                for digit in digit_range:
                    digit_frequencies[digit] = position_counters[i].get(digit, 0)
                
                # 找出频率最低的数字们
                min_frequency = min(digit_frequencies.values())
                min_freq_digits = [digit for digit, freq in digit_frequencies.items() if freq == min_frequency]
                
                # 如果有多个频率最低的数字，随机选择一个
                predicted_digit = random.choice(min_freq_digits)
                predicted_numbers.append(predicted_digit)
            else:
                # 如果没有历史数据，随机选择
                if i == 6:  # 第7位数字范围是0-14
                    predicted_numbers.append(random.randint(0, 14))
                else:  # 前6位数字范围是0-9
                    predicted_numbers.append(random.randint(0, 9))
        
        logger.info(f"最低频率分析预测结果: {predicted_numbers}")
        return predicted_numbers
    
    def ensemble_prediction_qxc(self, predictions):
        """集成多种预测方法的结果"""
        if not predictions:
            # 返回数字列表而不是字符串
            return [random.randint(0, 9) if i < 6 else random.randint(0, 14) for i in range(7)]
        
        # 为每个位置统计预测结果
        position_votes = [Counter() for _ in range(7)]
        
        for method, prediction in predictions.items():
            if prediction and len(prediction) == 7:
                for i, digit in enumerate(prediction):
                    position_votes[i][digit] += 1
        
        # 为每个位置选择得票最多的数字
        final_numbers = []
        for i in range(7):
            if position_votes[i]:
                most_common = position_votes[i].most_common(1)[0][0]
                final_numbers.append(most_common)
            else:
                # 根据位置设置不同的随机范围
                if i == 6:  # 第7位数字范围是0-14
                    final_numbers.append(random.randint(0, 14))
                else:  # 前6位数字范围是0-9
                    final_numbers.append(random.randint(0, 9))
        
        return final_numbers
    
    def prepare_ml_data_qxc(self, historical_data):
        """为机器学习准备七星彩数据"""
        X = []
        y = []
        
        # 使用滑动窗口方法
        window_size = 8
        for i in range(len(historical_data) - window_size):
            # 使用前window_size期的数据作为特征
            features = []
            for j in range(window_size):
                record = historical_data[i + j]
                # 将7位数字转换为特征
                digits = [int(d) for d in record['numbers']]
                features.extend(digits)
                
                # 添加统计特征
                features.append(np.mean(digits))  # 平均值
                features.append(np.std(digits))   # 标准差
                features.append(sum(d % 2 for d in digits))  # 奇数个数
                features.append(sum(1 for d in digits if d >= 5))  # 大数个数
            
            X.append(features)
            
            # 目标是下一期的号码
            target_record = historical_data[i + window_size]
            target_digits = [int(d) for d in target_record['numbers']]
            y.append(target_digits)
        
        return np.array(X), np.array(y)
    
    def calculate_confidence(self, historical_data, prediction):
        """计算预测的置信度"""
        # 基于历史数据的一致性计算置信度
        base_confidence = 0.25  # 基础置信度（七星彩难度较高）
        
        # 根据数据量调整
        data_bonus = min(0.15, len(historical_data) / 500)
        
        # 根据预测号码的合理性调整
        reasonability_bonus = 0.1
        if prediction and len(prediction) == 7:
            # 检查数字分布的合理性
            # prediction现在是数字列表而不是字符串
            if isinstance(prediction, list):
                digits = prediction
            else:
                digits = [int(d) for d in prediction]
            
            odd_count = sum(1 for d in digits if d % 2 == 1)
            big_count = sum(1 for d in digits if d >= 5)
            
            # 合理的奇偶和大小分布会增加置信度
            if 2 <= odd_count <= 5 and 2 <= big_count <= 5:
                reasonability_bonus = 0.15
        
        total_confidence = base_confidence + data_bonus + reasonability_bonus
        return min(0.85, total_confidence)  # 最高85%置信度